 .comment \

	zmp 1.5 overlay, version 1.0
	computer: ampro lb+
	terminal: wyse 50   (optional)

	- works with or without nzcom present.
	- displays baud rate, data bits, stop bits and parity in the
	  wyse 50's host field (top line, above scrollable screen)
          if you set the equate hostline true. otherwise these are
	  just shown on your screen when set.
	- provides a dtrexit equate which, when set true, will prompt
	  you to see if you want DTR signal turned off when you exit
	  ZMP. i have an old bell dataphone 1200 modem, and the only
	  way i've found to keep it from answering my phone automatically
	  when i don't want it to is to keep DTR off except when in a
	  modem program. DTR is automatically turned on on entry to ZMP
	  in any case. the prompt allows you to exit a terminal session 
	  temporarily to your o/s level for whatever reason, without
	  disconnecting your session.
	- screen print function not currently implemented.
	- be sure to set ALL config equates (in praticular the disk/user
	  for overlay files).

						al grabauskas
						12/6/88

			i'm reachable at:	lillipute z-nodes 1&2
						(312) 649-1730
						(312) 664-1730

						the advocate
						(312) 939-4411

\

;-----------------------------------------------------------------------------
;
;	Sample Overlay for ZMP (Z-Modem Program)
;
;	Name	ZMO-BLNK.Z80
;
;	Dated Sep 14, 1988
;
;	Written by -
;	  Ron Murray, c/o Z-Node 62, 061-9-450-0200, Perth, Western Australia.
;
;	Modified to ZMP v1.2 standard rjm 15/9/88
;	Modified to ZMP v1.3 standard rjm 11/10/88
;	Modified to ZMP v1.4 standard rjm 20/11/88
; 89/04/12 - Modified to ZMP v1.5		- George Conover
;
;
;-----------------------------------------------------------------------------
;
;
;	System-dependent code overlay for ZMODEM
;
;
;
;    Insert your own code as necessary in this file. Code contained herein
; has been written in Z80 code for use with M80 or SLR. Assemble as follows:
;
;	SLR ZMO-xx01/h
;	MLOAD ZMP.COM=ZMODEM.COM,ZMO-xx01.HEX
; or
;	M80 =ZMO-xx01.Z80
;	RELHEX ZMO-xx01
;	MLOAD ZMP.COM=ZMODEM.COM,ZMO-xx01.HEX
;
;
;       (Don't use L80 without changing the source for assembly as a
;         cseg file.)
;
;-----------------------------------------------------------------------------
;
;
; Notes on modifying this file:
;
;    C requires that functions do not change either index register (IX or IY).
; If your overlay requires either of these to be changed, ensure they are
; restored to the original values on return.
;    Since collecting parameters from C functions can be tricky, only change
; the parts marked 'Insert your own code here'. Do NOT modify the jump
; table at the start. Do NOT modify the entry/exit sections of each
; function. Do NOT pass 'GO'. Do NOT collect $200.
;    Apart from defining modem functions, this file also defines terminal
; characteristics. Examples provided are for ADM-3A (with a few of my own
; additions). Modify to suit your own terminal. An inline print routine
; is provided for printing strings in the usual way: usage is
;
;	call	print
;	db	'required string',0
;
;-----------------------------------------------------------------------------
;
;
;    Don't forget to set your clock speed at the clkspd variable.
;
;
;    If you find your overlay exceeds the maximum size (currently 0400h),
; you will have to contact me for another version. If too many people need 
; to do it, we haven't allowed enough room.
;
; Ron Murray 15/8/88
;
;
;
;---------------------------------------------------------------------------

false	equ	0
true	equ	not false

;------------------------------------------------------------------------------

; User-set variables: 

; configuration equates for ampro overlay
dtrexit	equ	true		; if true, the userout: routine will prompt
				; you to see if you want to turn off DTR
				; completely on exiting ZMP. DTR is automati-
				; cally turned on when entering ZMP. turning
				; DTR off prevents some modems from auto-
				; answering the phone. the prompt allows you
				; to leave a session temporarily to your o/s
				; and not disconnect.

hostline	equ	true		; controls whether your line parameters are
				; displayed in the host field of a wyse 
				; terminal at all times in ZMP, or if they
				; are simply echoed to the screen when set.

clkspd	equ	4		; Processor clock speed in MHz
debug	equ	false		; to allow debugging of overlay with Z8E etc.
; end configuration equates for ampro overlay

;Set the following two equates to the drive and user area which will contain
;   ZMP's .OVR files, .CFG file, .FON file and .HLP file. Set both to zero
;   (null) to locate them on the drive from which ZMP was invoked.

overdrive	equ	'F'	; Drive to find overlay files on ('A'-'P')
overuser	equ	15	; User area to find files

;------------------------------------------------------------------------------


; NOT user-set variables

userdef	equ	0145h		; origin of this overlay
				; This address should not change with
				; subsequent revisions.
mspeed	equ	03ch		; location of current baud rate. 
ovsize	equ	0400h		; max size of this overlay

; ampro definitions

ioint	equ	57		;BIOS call of initialization routine
siob	equ	52h		;Relative location in bios
siob1	equ	53h		;*eag*
siob3	equ	55h		;*eag*
siob5	equ	57h		;*eag*
ct1	equ	42h		;*eag*

;	port definitions

modctl	equ	8ch		; modem control port b
moddat	equ	88h		; modem data port b

;	bit definitions

mdrcvb	equ	01h		; Modem receive ready bit (dav)
mdsndb	equ	04h		; Modem send ready bit

mdparer	equ	010h		; parity error
mdovrrn	equ	020h		; overrun error
mdfram	equ	030h		; framing error
mderrf	equ	mdparer+mdovrrn+mdfram ; *eag*

mddtrof	equ	068h		; turn off dtr, rts
mddtron	equ	0eah		; restore normal, 8 bits, rts on, etc.

; end ampro specific equates

esc	equ	1bh
ctrlq	equ	11h
cr	equ	0dh
lf	equ	0ah
bdos	equ	5

	.z80			; use z80 code
	aseg			; absolute

	 if	debug
	org	100h		; so you can debug it with cebug, zsid, etc
	 else
	org	userdef
	 endif


esc	equ	1bh
ctrlq	equ	11h
cr	equ	0dh
lf	equ	0ah
bdos	equ	5

codebgn	equ	$

;Jump table for the overlay: do NOT change this
jump_tab:
	jp	scrnpr		; screen print
	jp	mrd		; modem read with timeout
	jp	mchin		; get a character from modem
	jp	mchout		; send a character to the modem
	jp	mordy		; test for tx buffer empty
	jp	mirdy		; test for character received
	jp	sndbrk		; send break
	jp	cursadd		; cursor addressing
	jp	cls		; clear screen
	jp	invon		; inverse video on
	jp	invoff		; inverse video off
	jp	hide		; hide cursor
	jp	show		; show cursor
	jp	savecu		; save cursor position
	jp	rescu		; restore cursor position
	jp	mint		; service modem interrupt
	jp	invec		; initialise interrupt vectors
	jp	dinvec		; de-initialise interrupt vectors
	jp	mdmerr		; test uart flags for error
	jp	dtron		; turn DTR on
	jp	dtroff		; turn DTR OFF
	jp	init		; initialise uart
	jp	wait		; wait seconds
	jp	mswait		; wait milliseconds
	jp	userin		; user-defined entry routine
	jp	userout		; user-defined exit routine
	jp	getvars		; get system variables
  	JP	SETPORT		; Set port (0 or 1)

; Spare jumps for compatibility with future versions
	jp	spare		; spare for later use
	jp	spare		; spare for later use
	jp	spare		; spare for later use
	jp	spare		; spare for later use
	jp	spare		; spare for later use
	jp	spare		; spare for later use

;
; Main code starts here
;
;Screen print function
scrnpr:
				; <== Insert your own code here
	call	print
	db	'This function not supported.',cr,lf,0
				; <== End of your own code
spare:
	ret

; User-defined entry routine: leave empty if not needed

;------------------------------------------------------------------------------
; this is a routine that locates the warm boot address whether nz-com is
; running or not and stores it at the word biospt. this allows access to 
; ampro specific offsets in the bios. (note that this is bios base addr+3).
;
; note that this assumes the nz-com bios released with nz-src.lbr (vers. 1.4)
; if that isn't what you have you'll likely need to modify what's below.

eyectof	equ	5ah		; Offset to "NZ-COM" eyecatcher
				;   from virtual bios base.
nzceye:	db	'NZ-COM'	; Eyecatcher to match
eyelen	equ	$-nzceye	; Length of eyecatcher

; end most likely user mods	----------------------------------------------

userin:
	push	hl
	push	de
	push	bc
	push	af

	ld	hl,(1)		; This is some bios address..
	ld	l,eyectof	; Hl = ptr to "NZ-COM" eyecatcher
	ld	de,nzceye	; Ptr to an internal copy of it
	ld	b,eyelen	; Length

nzckloop:
	ld	a,(de)		; Get a char
	cp	(hl)		; Compare to char at hl
	jr	nz,nonzc	; No nz-com
	inc	hl		; Bump ptr
	inc	de		; Bump ptr
	dec	b		; Decrement length
	jr	nz,nzckloop	; Repeat if apropos

	ld	a,(109h)	; get pointer to ENV descriptor
	ld	l,a
	ld	a,(10ah)
	ld	h,a
	inc	hl		; bump past jp opcode to console stat vector
	ld	e,(hl)		; Get real console status vector
	inc	hl
	ld	d,(hl)
	ex	de,hl		; Put it in hl
	dec	hl		; Convert to warm boot vector
	dec	hl
	dec	hl
	jr	biosret		; And return bios addr in biospt

nonzc:
	ld	hl,(1)		; Get original pointer

biosret:
	ld	(biospt),hl	; and save it
	call	initall		; set up rest of the details
	call	dtron		; make sure DTR is set
	pop	af		; Restore regs and return
	pop	bc
	pop	de
	pop	hl
	ret

; User-defined exit routine: leave empty if not needed
userout:
	call	print		; kill host message display on wyse
	db	esc,'A31',cr,0	; host msg field = dim underscore

	 if	dtrexit
	call	print		; dtr off yet?
	db	'Kill DTR? (default no) ',0
	call	cyn		; get yes/no answer
	ret	nz		; not a "yes"
	jp	dtroff		; do it
	 else
	ret
	 endif			; if dtrexit

;
; Y/N input from console
;
cyn:
	push	bc		; save regs
	push	de
	push	hl
	ld	c,1
	call	bdos		; print it
	or	a,' '		; make small case
	cp	a,'y'		; yes?
	pop	hl
	pop	de
	pop	bc
	ret

;Get a character from the modem: return in HL
mchin:
	push	bc
				; <== Insert your own code here

	in	a,(moddat)	; in modem data port

				; <== End of your own code

	ld	l,a		; put in HL
	ld	h,0
	or	a		; set/clear Z
	pop	bc
	ret

;Send a character to the modem
mchout:
	ld	hl,2		; get the character
	add	hl,sp
	ld	a,(hl)
				; <== Insert your own code here

	out	(moddat),a	; out modem data port

				; <== End of your own code
	ret			; done

;Test for output ready: return TRUE (1) in HL if ok
mordy:
				; <== Insert your own code here

	in	a,(modctl)	; in modem control port
	and	mdsndb		; bit to test for send ready
	jr	z,monr		; modem not ready
	ld	hl,1		; indicate ready
	jr	mordyret
monr:	ld	hl,0		; indicate not ready
mordyret:
				; <== End of your own code

	ld	a,l		; set/clear Z
	or	a
	ret

;Test for character at modem: return TRUE (1) in HL if so
mirdy:
				; <== Insert your own code here

	in	a,(modctl)	; in modem control port
	and	mdrcvb		; bit to test for receive ready
	jr	z,minr		; modem not ready
	ld	hl,1		; indicate ready
	jr	mirdyret
minr:	ld	hl,0		; indicate not ready
mirdyret:
				; <== End of your own code
	ld	a,l		; set/clear Z
	or	a
	ret

;Send a break to the modem: leave empty if your system can't do it
sndbrk:
				; <== Insert your own code here

	ld	a,5		; *eag*
	out	(modctl),a	; send to the status port
	ld	a,mddtrof	; turn off dtr, rts, send break
	out	(modctl),a	; *eag*

				; <== end of your own code

	ld	hl,300		; wait 300 mS
	call	waithlms

				; <== insert your own code here
				; To restore


				; <== End of your own code
	ret


;Test UART flags for error: return TRUE (1) in HL if error.
mdmerr:
				; <== Insert your own code here

	in	a,(modctl)	; in modem control port
	and	mderrf		; bits to test: parity, overrun, framing
	jr	z,mnerr		; no error
	ld	hl,1		; indicate error
	jr	merrret
mnerr:	ld	hl,0		; indicate no error
merrret:
				; <== End of your own code
	ld	a,l		; set/clear Z
	or	a
	ret

;Turn DTR ON
dtron:
				; <== Insert your own code here

	ld	a,5		; *eag*
	out	(modctl),a	; *eag*
	ld	a,mddtron	; restore normal, 8 bits, rts on, etc.
	out	(modctl),a	; *eag*

				; <== End of your own code
	ret

;Turn DTR OFF
dtroff:
				; <== Insert your own code here

	ld	a,5		; *eag*
	out	(modctl),a	; send to the status port
	ld	a,mddtrof	; turn off dtr, rts, send break
	out	(modctl),a	; *eag*

				; <== End of your own code
	ret



;Initialise the uart

init:

	ld	hl,2		; get parameters
	add	hl,sp
	ex	de,hl
	call	getparm		; in HL
	ld	(brate),hl	; baud rate
	call	getparm
	ld	(parity),hl	; parity
	call	getparm
	ld	(data),hl	; data bits (BINARY 7 or 8)
	call	getparm
	ld	(stop),hl	; stop bits (BINARY 1 or 2)


				; <== Insert your own code here
				; using values below
;*eag*	begin insertion

initall:			; alternate entry point for userin
	ld	de,(brate)	; Code to de
	ld	hl,baudtb	; Offset into table
	add	hl,de
	ld	a,(hl)		; Fetch code
	or	a		; 0? (means unsupported code)
	jp	z,pbexit	; exit if so
	ld	(bsave1),a	; Save it

	ld	a,(brate)	; get brate
	ld	(mspeed),a	; don't forget to load mspeed with the
				; current brate value if the new rate is
				; valid. 

	ld	hl,baudtx	; Offset into second table
	add	hl,de
	ld	a,(hl)		; Get second value
	ld	(bsave2),a	; Save it also

	ld	hl,(biospt)	; Get location of bios
	ld	l,ct1		; Add 42h to reach ct1 in i/o table
	ld	a,47h
	ld	(hl),a
	inc	hl		; Move to next location
	ld	a,(bsave1)	; Get first table value
	ld	(hl),a		; Store it
	ld	a,(bsave2)	; Get second table value
	ld	b,a		; And save it
	ld	l,siob1		; Move ahead to siob+1 values
	ld	a,(hl)		; Get current value
	and	3fh
	or	b		; Or it with second value
	ld	(hl),a		; Store it in work table
	inc	hl
	inc	hl
	ld	a,(hl)		; Get last value and make
	or	80h		; Sure msb is set
	ld	(hl),a		; Put it back in working table

	ld	a,(data)	; 7 or 8 data bits
	sbc	a,7		; kill offset
	ld	h,0
	ld	l,a
	ld	de,bittbl	; Load lookup table
	add	hl,de		; get bit pattern
	ld	c,(hl)		; Save selection value
	ld	hl,(biospt)	; Get bios address
	ld	l,siob3		; Move to siob+3
	ld	a,(hl)		; Wr5 info
	and	9fh		; Mask
	or	c		; Add selection
	ld	(hl),a		; Store it
	ld	a,c		; Get selection
	rla
	ld	c,a		; Shift selection left
	ld	l,siob5		; Move to siob+5
	ld	a,(hl)		; Wr3 info
	and	3fh		; Mask
	or	c
	ld	(hl),a		; Store it

	ld	a,(parity)	; get parity
	cp	'N'
	jr	z,parno
	cp	'E'
	jr	z,parev
	cp	'O'
	jr	z,parod
	jp	pbexit

parno:	ld	c,00h
	jr	setpar

parev:	ld	c,03h
	jr	setpar

parod:	ld	c,01h

setpar:	ld	hl,(biospt)	; Get bios address
	ld	l,siob1		; Go to siob+1
	ld	a,(hl)
	and	0fch
	or	c
	ld	(hl),a

	ld	a,(stop)	; stop bits
	sbc	a,1		; kill offset
	ld	h,0
	ld	l,a
	ld	de,stptbl	; bit patterns
	add	hl,de		; ptr to bit pattern
	ld	c,(hl)		; get result
	ld	hl,(biospt)	; Get bios address
	ld	l,53h		; Shift to bios+1
	ld	a,(hl)
	and	0f3h
	or	c
	ld	(hl),a

	ld	hl,(brate)	; get baud code
	sla	l		; *2
	sla	l		; *4
	ld	de,pbauds	; base of printable baud table
	add	hl,de		; printable baud
	ld	de,baudshw	; dest
	ld	bc,4		; len
	ldir			; move it

	ld	a,(parity)	; display that
	ld	(parshw),a

	ld	a,(data)	; display that
	add	a,'0'		; make ascii
	ld	(bitshw),a

	ld	a,(stop)	; display that
	add	a,'0'		; make ascii
	ld	(stopshw),a

	call	print		; display stuff on wyse

;	the next few lines set the host message field on the wyse-50
;	to the following string, which displays your currently set
;	line parameters (baud, bits, parity and stop bits) in a 
;	permanent host field at the top of your terminal. if hostline
;	equate is not set true, they will just be shown on the screen
;	whenever they are set.

	 if	hostline
	db	esc,'A3p'	; host msg field = dim underscore
	db	esc,"F"		; set set message
	 endif

	db	'          Baud: '
baudshw:
	db	'    '		; printable baud rate
	db	' Bits: '
bitshw:
	db	' '		; bits per char
	db	' Parity: '
parshw:
	db	' '		; parity
	db	' Stop: '
stopshw:
	db	' '		; stop bits

	db	cr,lf,0

	jp	ioinit		; Do the initialization

;*eag*	end insertion

				; <== End of your own code
	ret

;*eag*	begin insertion

ioinit:

	ld	a,ioint		; Offset into bios jump table
	ld	hl,(biospt)	; Address of bios in hl
	ld	l,a		; Add offset
	jp	(hl)		; Go there with auto return

;	routine to handle unsupported baud rates

pbexit:
	call print
	db	'Unsupported.',cr,lf,0
	ret

; table of baud rate divisors for supported rates

baudtb:	db	0,208,139	; 110,300,450
	db	208,0,104	; 600,710,1200
	db	52,26,13,0	; 2400,4800,9600,19200

baudtx:	db	0,80h,80h
	db	40h,0,40h
	db	40h,40h,40h,0

pbauds:	db	' 110',' 300',' 450',' 600',' 710'
	db	'1200','2400','4800','9600',' 19K'

bsave1:	db	0		; Current setting from
bsave2:	db	0		; Tables - uninitialized

bittbl:	db	20h,60h		; 7 or 8 data bits

stptbl:	db	04h,0ch		; 1 or 2 stop bits

biospt:	dw	0

;*eag*	end insertion

;--------------------------------------------------------------------------

stop:	dw	1		; stop bits
parity:	dw	'N'		; parity
data:	dw	8		; data bits
brate:	dw	5		; baud rate:

;--------------------------------------------------------------------------
;Values of brate for each baud rate
;
; baud rate    brate
;
;   110		 0
;   300		 1
;   450		 2
;   600		 3
;   710		 4
;  1200		 5
;  2400		 6
;  4800		 7
;  9600		 8
; 19200		 9
; 38400		10
; 57600         11
; 76800         12
;

;
; Set the port. ZMP supplies either 0 or 1 as a parameter.
;
setport:
	ld	hl,2		; get port number
	add	hl,sp
	ex	de,hl
	call	getparm		; in HL (values are 0 and 1)

				; <== Insert your own code here

				; <== End of your own code
	ret
;****************************************************************************
;Video terminal sequences: these are for ADM-3A: Modify as you wish
;Cursor addressing: 
cursadd:
	ld	hl,2		; get parameters
	add	hl,sp
	ex	de,hl
	call	getparm		; in HL
	ld	(row),hl	; row
	call	getparm
	ld	(col),hl	; column
				; <== Insert your own code here
				; using values in row and col
	call	print
	db	esc,'=',0	; ADM-3A leadin
	ld	a,(row)		; row first
	add	a,' '		; add offset
	call	cout
	ld	a,(col)		; sane for column
	add	a,' '
	call	cout
				; <== end of your own code
	ret

row:	ds	2		; row
col:	ds	2		; column

;clear screen:
cls:
	call	print
	db	01ah,0
	ret

;inverse video on:
invon:
	call	print
	db	esc,')',0
	ret

;inverse video off:
invoff:
	call	print
	db	esc,'(',0
	ret

;turn off cursor:
hide:
	call	print
	db	esc,'`0',0	; wyse 50 cursor off
	ret

;turn on cursor:
show:
	call	print
	db	esc,'`1',0	; wyse 50 cursor on
	ret

;save cursor position:
savecu:
	ret

;restore cursor position:
rescu:
	ret

;****************************************************************************

;Service modem interrupt:
mint:
	ret			; my system doesn't need this

;Initialise interrupt vectors:
invec:
	ret			; ditto

;De-initialise interrupt vectors:
dinvec:
	ret			; ditto

;****************** End of user-defined code ********************************
;		Do not change anything below here.

;Modem character test for 100 ms
mrd:
	push	bc		; save bc
	ld	bc,100		; set limit
mrd1:
	call	mirdy		; char at modem?
	jr	nz,mrd2		; yes, exit
	ld	hl,1		; else wait 1ms
	call	waithlms
	dec	bc		; loop till done
	ld	a,b
	or	c
	jr	nz,mrd1
	ld	hl,0		; none there, result=0
	xor	a
mrd2:
	pop	bc
	ret

; Inline print routine: destroys A and HL

print:
	ex	(sp),hl		; get address of string
ploop:
	ld	a,(hl)		; get next
	inc	hl		; bump pointer
	or	a		; done if zero
	jr	z,pdone
	call	cout		; else print
	jr	ploop		; and loop
pdone:
	ex	(sp),hl		; restore return address
	ret			; and quit

;
;Output a character in A to the console
;
cout:
	push	bc		; save regs
	push	de
	push	hl
	ld	e,a		; character to E
	ld	c,2
	call	bdos		; print it
	pop	hl
	pop	de
	pop	bc
	ret

;Wait(seconds)
wait:
	ld	hl,2
	add	hl,sp
	ex	de,hl		; get delay size
	call	getparm
				; fall thru to..
;Wait seconds in HL
waithls:
	push	bc		; save bc
	push	de		; de
	push	ix		; and ix
	ld	ix,0		; then point ix to 0
				; so we don't upset memory-mapped i/o

;Calculate values for loop constants. Need to have two loops to avoid
;   16-bit overflow with clock speeds above 9 MHz.

outerval	equ	(clkspd / 10) + 1
innerval	equ	(6667 / outerval) * clkspd

wait10:
	ld	b,outerval

wait11:
	ld	de,innerval

wait12:
	bit	0,(ix)		; time-wasters
	bit	0,(ix)
	bit	0,(ix)		; 20 T-states each
	bit	0,(ix)
	bit	0,(ix)
	bit	0,(ix)
	dec	de
	ld	a,e
	ld	a,d
	or	e
	jr	nz,wait12	; 150 T-states per inner loop
	djnz	wait11		; decrement outer loop
	dec	hl		; ok, decrement count in hl
	ld	a,h
	or	l
	jr	nz,wait10
	pop	ix		; done -- restore ix
	pop	de		; de
	pop	bc		; and bc
	ret

;Wait milliseconds
mswait:
	ld	hl,2
	add	hl,sp
	ex	de,hl		; get delay size
	call	getparm
				; fall thru to..
;Wait milliseconds in HL
waithlms:
	push	de
w1ms0:
	ld	de,39 * clkspd
w1ms1:
	dec	de
	ld	a,d
	or	e
	jr	nz,w1ms1
	dec	hl
	ld	a,h
	or	l
	jr	nz,w1ms0
	pop	de
	ret

;Get next parameter from (de) into hl
getparm:
	ex	de,hl		; get address into hl
	ld	e,(hl)		; get lo
	inc	hl
	ld	d,(hl)		; then hi
	inc	hl		; bump for next
	ex	de,hl		; result in hl, address still in de
	ret

;Get address of user-defined variables

getvars:
	ld	hl,uservars
	ret

uservars:
	dw	overdrive	; .OVR etc. drive/user
	dw	overuser


	 if	($ - codebgn) gt ovsize
toobig:	jp	errval		; Overlay too large!
	 endif

	end
